use serde_json::{Value, Result};
use std::collections::HashMap;
use std::error::Error;
use std::time::Duration;
use std::thread::sleep;

struct DataSourceLocalDir {
    _path: str
}

impl DataSource for DataSourceLocalDir {
    fn new(name: str, params: Value) {
        /*
        if "path" not in param:
            raise _getConfigError(source, BackendType.LOCAL_DIR, "no", "path")
        if not os.path.isabs(param["path"]):
            raise _getConfigError(source, BackendType.LOCAL_DIR, "invalid", "path")
        */
        DataSourceLocalDir {
            _path: params["path"].as_str().unwrap()
        }
    }

    fn get_disk_cache_info(&self) -> CacheInfo {
        None
    }

    fn get_site_data(&self, site_list: Option<Vec<&str>>) -> HashMap<str, SiteData> {
        /*
        file content example:
          {
              "info": {
                  XXXX
              }
              "data": {
                  "alpine": {
                      "sources": [
                          {
                              "url": "https://dl-cdn.alpinelinux.org/"
                          }
                      ],
                      "mirrors": [
                          {
                              "name": "XXX",
                              "description": "XXX",
                              "url": "https://dl-cdn.alpinelinux.org/",
                              "address-families": ["ip", "ip6"]
                          }
                      ]
                  }
              }
          }
        */

        let mut ret: HashMap<str, SiteData> = HashMap::new();

        if !Path::new(&self._path).exists() {
            return ret;
        }

        if !Path::new(&self._path).is_dir() {
            return Err(format!("\"{}\" is not a directory", self._path));
        }

        if site_list.is_none() {
            for entry in std::fs::read_dir(&self._path)? {
                let fullfn = entry?.path();
                if let Some(name) = fullfn.file_stem().and_then(|n| n.to_str()) {
                    ret.insert(name.to_string(), fullfn.to_string_lossy().to_string());
                }
            }
        } else {
            for n in site_list {
                let fullfn = format!("{}/{}.json", self._path, n);
                if Path::new(&fullfn).exists() {
                    if !Path::new(&self._path).is_file() {
                        return Err(format!("\"{}\" is not a file", fullfn));
                    }
                    ret.insert(n, fullfn);
                }
            }
        }

        for (name, fullfn) in ret {
            let mut file = File::open(&fullfn)?;
            let mut file_content = String::new();
            file.read_to_string(&mut file_content)?;

            let json_value: Value = serde_json::from_str(&file_content)?;
            let mut entry = ret.entry(name).or_insert_with(|| {
                json_value.as_object().map_or(HashMap::new(), |o| {
                    let mut entry = HashMap::new();
                    if let Some(sources) = o.get("sources") {
                        if let Some(sources_array) = sources.as_array() {
                            entry.insert("sources".to_string(), sources_array.clone());
                        }
                    }
                    if let Some(mirrors) = o.get("mirrors") {
                        if let Some(mirrors_array) = mirrors.as_array() {
                            entry.insert("mirrors".to_string(), mirrors_array.clone());
                        }
                    }
                    entry
                })
            });

            if let Some(sources) = json_value.get("sources") {
                if let Some(sources_array) = sources.as_array() {
                    if let Some(existing_sources) = entry.get_mut("sources") {
                        existing_sources.as_array_mut().map(|arr| {
                            arr.extend(sources_array.iter().cloned());
                        });
                    } else {
                        entry.insert("sources".to_string(), sources_array.clone());
                    }
                }
            }
            if let Some(mirrors) = json_value.get("mirrors") {
                if let Some(mirrors_array) = mirrors.as_array() {
                    if let Some(existing_mirrors) = entry.get_mut("mirrors") {
                        existing_mirrors.as_array_mut().map(|arr| {
                            arr.extend(mirrors_array.iter().cloned());
                        });
                    } else {
                        entry.insert("mirrors".to_string(), mirrors_array.clone());
                    }
                }
            }
        }

        Ok(ret)
    }
}












    }
}